home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Textfiles / zines / Phrack / Phrack Issue 51.sit / Phrack51 / P51-10 < prev    next >
Text File  |  1997-09-01  |  7KB  |  281 lines

  1. ---[  Phrack Magazine   Volume 7, Issue 51 September 01, 1997, article 10 of 17
  2.  
  3.  
  4. -------------------------[  Scanning for RPC Services
  5.  
  6.  
  7. --------[  halflife <halflife@infonexus.com>
  8.  
  9.  
  10. Remote Procedure Language is a specification for letting procedures be
  11. executable on remote machines.  It is defined in rfc1831.  It has a number of 
  12. good traits, and if you run SunOS or Solaris, you are almost required to make 
  13. use of it to some degree.
  14.  
  15. Unfortunately, there are vulnerabilities in some RPC services that have
  16. caused many machines to be penetrated.  Many administrators block access to 
  17. portmapper (port 111) in an effort to deny external users access to their weak 
  18. RPC services.
  19.  
  20. Unfortunately, this is completely inadequate.  This article details how 
  21. trivial it is to do a scan for specific RPC program numbers.  The scan can be 
  22. performed relatively quickly, and in many cases will not be logged.
  23.  
  24. First, a little information about RPC itself; when I refer to RPC, I am only 
  25. referring to ONC RPC, and not DCE RPC.  RPC is a query/reply-based system. You 
  26. send an initial query with the program number you are interested in, the 
  27. procedure number, any arguments, authentication, and other needed parameters. 
  28. In response, you get whatever the procedure returns, and some indication of 
  29. the reason for the failure if it failed.
  30.  
  31. Since RPC was designed to be portable, all arguments must be translated into 
  32. XDR.  XDR is a data encoding language that superficially reminds me a little 
  33. bit of Pascal (at least, as far as strings are concerned). If you want more 
  34. information on XDR, it is defined in rfc1832.
  35.  
  36. As you probably surmised by now, RPC programs are made up of various 
  37. procedures.  There is one procedure that always exists, it is procedure 0. 
  38. This procedure accepts no arguments, and it does not return any value (think 
  39. void rpcping(void)).  This is how we will determine if a given port holds a 
  40. given program, we will call the ping procedure!
  41.  
  42. So now we have a basic idea on how to determine if a given port is running
  43. a given RPC program number.  Next we need to determine which UDP ports are
  44. listening.  This can be done a number of ways, but the way I am using is
  45. to connect() to the port and try write data.  If nothing is there, we
  46. will (hopefully) get a PORT_UNREACH error in errno, in which case we know
  47. there is nothing on that port.
  48.  
  49. In the given code, we do a udp scan, and for every listening udp port, we
  50. try to query the ping procedure of the program number we are scanning for.
  51. If we get a positive response, the program number we are looking for exists
  52. on that port and we exit.
  53.  
  54. <++> RPCscan/Makefile
  55. CC=gcc
  56. PROGNAME=rpcscan
  57. CFLAGS=-c
  58.  
  59. build: checkrpc.o main.o rpcserv.o udpcheck.o
  60.     $(CC) -o $(PROGNAME) checkrpc.o main.o rpcserv.o udpcheck.o
  61.  
  62. checkrpc.o:
  63.     $(CC) $(CFLAGS) checkrpc.c
  64.  
  65. main.o:
  66.     $(CC) $(CFLAGS) main.c
  67.  
  68. rpcserv.o:
  69.     $(CC) $(CFLAGS) rpcserv.c
  70.  
  71. udpcheck.o:
  72.     $(CC) $(CFLAGS) udpcheck.c
  73.  
  74. clean:
  75.     rm -f *.o $(PROGNAME)
  76. <-->
  77. <++> RPCscan/checkrpc.c
  78. #include <stdio.h>
  79. #include <stdlib.h>
  80. #include <unistd.h>
  81. #include <sys/time.h>
  82. #include <sys/socket.h>
  83. #include <rpc/rpc.h>
  84. #include <netdb.h>
  85.  
  86. extern struct sockaddr_in *saddr;
  87.  
  88. int
  89. check_rpc_service(long program)
  90. {
  91.     int sock = RPC_ANYSOCK;
  92.     CLIENT *client;
  93.     struct timeval timeout;
  94.     enum clnt_stat cstat;
  95.  
  96.     timeout.tv_sec = 10;
  97.     timeout.tv_usec = 0;
  98.     client = clntudp_create(saddr, program, 1, timeout, &sock);
  99.     if(!client)
  100.         return -1;
  101.     timeout.tv_sec = 10;
  102.     timeout.tv_usec = 0;
  103.     cstat = RPC_TIMEDOUT;
  104.     cstat = clnt_call(client, 0, xdr_void, NULL, xdr_void, NULL, timeout);
  105.     if(cstat == RPC_TIMEDOUT)
  106.     {
  107.         timeout.tv_sec = 10;
  108.         timeout.tv_usec = 0;
  109.         cstat = clnt_call(client, 0, xdr_void, NULL, xdr_void, NULL, timeout);
  110.     }
  111.     clnt_destroy(client);
  112.     close(sock);
  113.     if(cstat == RPC_SUCCESS)
  114.         return 1;
  115.     else if(cstat == RPC_PROGVERSMISMATCH)
  116.         return 1;
  117.     else return 0;
  118. }
  119. <-->
  120. <++> RPCscan/main.c
  121. #include <stdio.h>
  122. #include <stdlib.h>
  123. #include <unistd.h>
  124.  
  125. int check_udp_port(char *, u_short);
  126. int check_rpc_service(long);
  127. long get_rpc_prog_number(char *);
  128. #define HIGH_PORT    5000
  129. #define LOW_PORT    512    
  130.  
  131. main(int argc, char **argv)
  132. {
  133.     int i,j;
  134.     long prog;
  135.     if(argc != 3)
  136.     {
  137.         fprintf(stderr, "%s host program\n", argv[0]);
  138.         exit(0);
  139.     }
  140.     prog = get_rpc_prog_number(argv[2]);
  141.     if(prog == -1)
  142.     {
  143.         fprintf(stderr, "invalid rpc program number\n");
  144.         exit(0);
  145.     }
  146.     printf("Scanning %s for program %d\n", argv[1], prog);
  147.     for(i=LOW_PORT;i <= HIGH_PORT;i++)
  148.     {
  149.         if(check_udp_port(argv[1], i) > 0)
  150.         {
  151.             if(check_rpc_service(prog) == 1)
  152.             {
  153.                 printf("%s is on port %u\n", argv[2], i);
  154.                 exit(0);
  155.             }
  156.         }
  157.     }
  158. }
  159. <-->
  160. <++> RPCscan/rpcserv.c
  161. #include <stdio.h>
  162. #include <stdlib.h>
  163. #include <unistd.h>
  164. #include <netdb.h>
  165. #include <ctype.h>
  166. #include <rpc/rpc.h>
  167.  
  168. long
  169. get_rpc_prog_number(char *progname)
  170. {
  171.     struct rpcent *r;
  172.     int i=0;
  173.  
  174.     while(progname[i] != '\0')
  175.     {
  176.         if(!isdigit(progname[i]))
  177.         {
  178.             setrpcent(1);
  179.             r = getrpcbyname(progname);
  180.             endrpcent();
  181.             if(!r)
  182.                 return -1;
  183.             else return r->r_number;
  184.         }
  185.         i++;
  186.     }
  187.     return atoi(progname);
  188. }
  189. <-->
  190. <++> RPCscan/udpcheck.c
  191. #include <stdio.h>
  192. #include <stdlib.h>
  193. #include <unistd.h>
  194. #include <string.h>
  195. #include <netdb.h>
  196. #include <netinet/in.h>
  197. #include <arpa/inet.h>
  198. #include <sys/types.h>
  199. #include <sys/socket.h>
  200. #include <sys/param.h>
  201. #include <sys/time.h>
  202. #include <sys/errno.h>
  203. extern int h_errno;
  204.  
  205. struct sockaddr_in *saddr = NULL;
  206.  
  207. int
  208. check_udp_port(char *hostname, u_short port)
  209. {
  210.     int s, i, sr;
  211.     struct hostent *he;
  212.     fd_set rset;
  213.     struct timeval tv;
  214.  
  215.     if(!saddr)
  216.     {
  217.         saddr = malloc(sizeof(struct sockaddr_in));
  218.         if(!saddr) return -1;
  219.  
  220.         saddr->sin_family = AF_INET;
  221.         saddr->sin_addr.s_addr = inet_addr(hostname);
  222.         if(saddr->sin_addr.s_addr == INADDR_NONE)
  223.         {
  224.             sethostent(1);
  225.             he = gethostbyname(hostname);
  226.             if(!he)
  227.             {
  228.                 herror("gethostbyname");
  229.                 exit(1);
  230.             }
  231.             if(he->h_length <= sizeof(saddr->sin_addr.s_addr))
  232.                 bcopy(he->h_addr, &saddr->sin_addr.s_addr, he->h_length);
  233.             else
  234.                 bcopy(he->h_addr, &saddr->sin_addr.s_addr, sizeof(saddr->sin_addr.s_addr));
  235.             endhostent();
  236.         }
  237.     }
  238.     saddr->sin_port = htons(port);
  239.     s = socket(AF_INET, SOCK_DGRAM, 0);
  240.     if(s < 0)
  241.     {
  242.         perror("socket");
  243.         return -1;
  244.     }
  245.     i = connect(s, (struct sockaddr *)saddr, sizeof(struct sockaddr_in));
  246.     if(i < 0)
  247.     {
  248.         perror("connect");
  249.         return -1;
  250.     }
  251.     for(i=0;i < 3;i++)
  252.     {
  253.         write(s, "", 1);
  254.         FD_ZERO(&rset);
  255.         FD_SET(s, &rset);
  256.         tv.tv_sec = 5;
  257.         tv.tv_usec = 0;
  258.         sr = select(s+1, &rset, NULL, NULL, &tv);
  259.         if(sr != 1)
  260.             continue;
  261.         if(read(s, &sr, sizeof(sr)) < 1)
  262.         {
  263.             close(s);
  264.             return 0;
  265.         }
  266.         else
  267.         {
  268.             close(s);
  269.             return 1;
  270.         }
  271.     }
  272.     close(s);
  273.     return 1;
  274. }
  275. <-->
  276.  
  277.  
  278. ----[  EOF
  279.  
  280.  
  281.